package com.dibang.app.mvp.abs;

import android.support.annotation.NonNull;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;

/**
 * Created by wxl on 2019/6/21.
 * bean 工厂
 */

public class BeanFactory {


    /**
     * 实体容器
     */
    private static HashMap<Class, Object> objects = new HashMap<>();


    /**
     * 通过构造进行初始化
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getInstance(@NonNull Class<T> clazz, Object... args) {
        synchronized (BeanFactory.class) {
            T t = (T) objects.get(clazz);
            synchronized (BeanFactory.class) {
                if (t == null) {
                    if (args == null || args.length == 0) {
                        t = generateObjectByClass(clazz);
                    } else {
                        t = generateObjectByClassWithArgs(clazz, args);
                    }
                    if (t != null) {
                        objects.put(clazz, t);
                    } else {
                        System.out.print(clazz.getName()+" - > 没有找到合适的构造方法");
                    }
                }
            }
            return t;
        }
    }


    /**
     * 通过构造函数new 一个对象
     *
     * @param clazz
     * @param args
     * @param <T>
     * @return
     */
    private static <T> T generateObjectByClassWithArgs(Class<T> clazz, Object... args) {
        try {
            return findExecuteDeclaredConstructor(clazz, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 根据参数找到正确的构造方法
     *
     * @param clazz
     * @param args
     * @return
     */
    private static <T> T findExecuteDeclaredConstructor(Class<T> clazz, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
        Constructor[] cs = clazz.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            // 获取构造函数的参数列表--->得到的是参数列表的类类型
            Class[] paramTypes = constructor.getParameterTypes();
            Class[] rightConstructorClass = findRightConstructorClass(paramTypes, args);
            if (rightConstructorClass != null) {
                constructor.setAccessible(true);
                return (T) constructor.newInstance(args);
            }
        }
        return null;
    }


    /**
     * 找到正确的构造函数
     *
     * @param paramTypes
     * @param args
     * @return
     */
    private static Class[] findRightConstructorClass(Class[] paramTypes, Object... args) {
        if (paramTypes == null || paramTypes.length == 0 || args == null || paramTypes.length != args.length) {
            return null;
        }
        Class[] rParamTypes = new Class[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++) {
            Class aClass = getClass(paramTypes[i], args[i]);
            if (aClass == null) {
                //System.out.println("参数不匹配 " + paramTypes[i].getName() + " -> " + args[i].getClass().getName());
                return null;
            } else {
                rParamTypes[i] = aClass;
            }
        }

        return rParamTypes;
    }


    /**
     * 找到对应的class
     * @param clazz
     * @param obj
     * @return
     */
    private static Class getClass(Class clazz, Object obj) {

        if (obj instanceof Integer) {
            if (clazz == int.class) {
                return int.class;
            }
        }
        if (obj instanceof Long) {
            if (clazz == long.class) {
                return long.class;
            }
        }
        if (obj instanceof Float) {
            if (clazz == float.class) {
                return float.class;
            }
        }
        if (obj instanceof Byte) {
            if (clazz == byte.class) {
                return byte.class;
            }
        }
        if (obj instanceof Boolean) {
            if (clazz == boolean.class) {
                return boolean.class;
            }
        }
        if (obj instanceof Character) {
            if (clazz == char.class) {
                return char.class;
            }
        }
        if (obj instanceof Short) {
            if (clazz == short.class) {
                return short.class;
            }
        }
        if (obj instanceof Double) {
            if (clazz == double.class) {
                return double.class;
            }
        }

        if (obj.getClass() == clazz) {
            return clazz;
        }

        return null;
    }


    /**
     * 无参构造
     *
     * @param clazz
     * @param <T>
     * @return
     */
    private static <T> T generateObjectByClass(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 移除元素
     *
     * @param clazz
     */
    public static void remove(Class<?>... clazz) {
        if (clazz == null || clazz.length == 0) return;
        for (int i = 0; i < clazz.length; i++) {
            if (objects.containsKey(clazz[i])) {
                objects.remove(clazz[i]);
            }
        }
    }

    /**
     * 清除所有元素
     */
    public static void clear() {
        objects.clear();
    }
}
